/*
	从IDA中粘贴的伪码，便于复现时快速还原被我重命名的变量
*/
__int64 __fastcall sub_1400011D0(__int64 hwind, int a2, __int64 a3, __int64 a4)
{
  __int64 v4; // rax
  __int64 result; // rax
  int v6; // eax
  unsigned int v7; // eax
  int i; // [rsp+40h] [rbp-528h]
  wchar_t *String1; // [rsp+48h] [rbp-520h]
  unsigned int v10; // [rsp+50h] [rbp-518h]
  unsigned int uid_map; // [rsp+58h] [rbp-510h]
  int v12; // [rsp+70h] [rbp-4F8h]
  LPCWSTR v13; // [rsp+78h] [rbp-4F0h]
  int v14[4]; // [rsp+118h] [rbp-450h] BYREF
  int v15[4]; // [rsp+128h] [rbp-440h] BYREF
  int v16[6]; // [rsp+138h] [rbp-430h] BYREF
  char v17[400]; // [rsp+150h] [rbp-418h] BYREF
  char v18[208]; // [rsp+2E0h] [rbp-288h] BYREF
  char flag_content[208]; // [rsp+3B0h] [rbp-1B8h] BYREF
  WCHAR v20[104]; // [rsp+480h] [rbp-E8h] BYREF
  unsigned int uid_map2; // [rsp+588h] [rbp+20h]

  uid_map2 = a4;
  if ( a2 == 0x110 )
  {
    qword_140017D38 = ((__int64 (__fastcall *)(__int64))qword_140017C90[15])(hwind);
    if ( !qword_140017D38 )
      qword_140017D38 = ((__int64 (*)(void))qword_140017C90[14])();
    sub_140001020(hwind);
    ((void (__fastcall *)(__int64, int *))qword_140017C90[13])(qword_140017D38, v16);
    ((void (__fastcall *)(__int64, int *))qword_140017C90[13])(hwind, v15);
    ((void (__fastcall *)(int *, int *))qword_140017C90[12])(v14, v16);
    Block = (LPCWSTR)malloc(0x384u L);
    ((void (__fastcall *)(int *, _QWORD, _QWORD))qword_140017C90[11])(v15, (unsigned int)-v15[0], (unsigned int)-v15[1]);
    ((void (__fastcall *)(int *, _QWORD, _QWORD))qword_140017C90[11])(v14, (unsigned int)-v14[0], (unsigned int)-v14[1]);
    ((void (__fastcall *)(int *, _QWORD, _QWORD))qword_140017C90[11])(v14, (unsigned int)-v15[2], (unsigned int)-v15[3]);
    for ( i = 0; i < 25; ++i )
    {
      Block[i] = (i + 66) ^ *((_WORD *)qword_1400167F0 + i);
      Block[i + 25] = (i + 66) ^ *((_WORD *)&qword_1400167F0[6] + i + 1);
      Block[i + 50] = (i + 66) ^ *((_WORD *)&qword_1400167F0[12] + i + 2);
      Block[i + 75] = (i + 66) ^ *((_WORD *)&qword_1400167F0[18] + i + 3);
      Block[i + 100] = (i + 66) ^ *((_WORD *)&qword_1400167F0[25] + i);
    }
    ((void (__fastcall *)(__int64, _QWORD, _QWORD, _QWORD, _DWORD, _DWORD, int))qword_140017C90[10])(
      hwind,
      0 L,
      (unsigned int)(v14[2] / 2 + v16[0]),
      (unsigned int)(v14[3] / 2 + v16[1]),
      0,
      0,
      1);
    if ( ((unsigned int (__fastcall *)(__int64))qword_140017C90[9])(a3) == 1000 )
    {
      result = 1 L;
    }
    else
    {
      v4 = ((__int64 (__fastcall *)(__int64, __int64))qword_140017C90[7])(hwind, 1000 L);
      ((void (__fastcall *)(__int64))qword_140017C90[8])(v4);
      result = 0 L;
    }
  }
  else
  {
    if ( a2 != 0x111 )
      return 0 L;
    switch ( (unsigned __int16)a3 )
    {
      case 1u:
        v10 = sub_140001A20(hwind);
        if ( v10 )
        {
          if ( (int)sub_140001FC0(hwind, v18) > 0 )
          {
			  // 重点可能在这里，v12应该为4
            v12 = sub_140002110(v18, v10);
            winproc(hwind, 273 L, 0x300 L, v12);
            result = 1 L;
          }
          else
          {
            result = 0 L;
          }
        }
        else
        {
          result = 0 L;
        }
        break;
      case 2u:
        ((void (__fastcall *)(__int64, _QWORD))qword_140017C90[6])(hwind, (unsigned __int16)a3);
        if ( Block )
          free((void *)Block);
        result = 1 L;
        break;
      case 0x300u:
        switch ( a4 )
        {
          case 1 L:
            String1 = (wchar_t *)(Block + 50);
            *((_WORD *)Block + 53) = 0;
            v6 = wcscmp(String1, &String2);
            break;
          case 2 L:
            String1 = (wchar_t *)(Block + 58);
            v6 = wcscmp(Block + 58, &String2);
            break;
          case 3 L:
            String1 = (wchar_t *)(Block + 50);
            *((_WORD *)Block + 53) = 32;
            v6 = wcscmp(String1, &String2);
            break;
          case 4 L:
            sub_140002E90(hwind);
            return 1 L;
          default:
            String1 = (wchar_t *)byte_1400132D0;
            v6 = wcscmp((const wchar_t *)byte_1400132D0, &String2);
            break;
        }
        if ( v6 )
        {
			// 程序会经过两次，第一次 v6 一定是空的
          v13 = Block + 75;
          wsprintfW(v20, Block, String1);
          ((void (__fastcall *)(__int64, WCHAR *, LPCWSTR, __int64))qword_140017C90[5])(hwind, v20, v13, 16 L);
          result = 1 L;
        }
        else
        {
			// 所以第一次会跑这里再检查一遍, uid_map 应该是与uid有关的值映射，可能与flag无关
			// 当uid = 835429 时， uid_map = 0xCBF65
          uid_map = sub_1400025E0(hwind);
          if ( uid_map )
          {
			  // 这个函数取了flag的长度，flag_content里存放的是原始的flag（虽然不知道是咋放进去的，全局变量？那没事了）
            if ( (int)sub_140002840(hwind, flag_content) > 0 )
            {
				//前两个检查都能过，也就是说第一次一定会跑到这里来
				//这两个函数可能是关键
				// 本函数调用后，v17内容发生变化，所以v17缓存了按一定规则加密的flag
				// flag的长度必须是8的整数倍（含flag{}符号），否则 v17 = NULL
				// 因此实际输入字符的长度可以为 2,10,18,...
              sub_140002900(flag_content, v17);
			  
			  // uid_map2 = a4，第一次a4必然走向default分支，因此此处要动态调试获取uid_map2的值，根据分析uid_map2,a4只和uid有关 
			  // 当uid = 835429时， uid_map2,a4 = 0x7ed9fee0
              // 令 v7 = 4 可以直接提示Success
			  // 由上述分析，传入这里的三个参数分别为一个与flag相关的，和两个与uid相关的
			  v7 = sub_140002A50(v17, uid_map, uid_map2);
              winproc(hwind, 0x111 L, 0x300 L, v7);
              result = 1 L;
            }
            else
            {
              result = 0 L;
            }
          }
          else
          {
            result = 0 L;
          }
        }
        break;
      default:
        return 0 L;
    }
  }
  return result;
}

__int64 __fastcall sub_140002A50(__int64 flag_enc, int uid_map, unsigned int uid_map2)
{
  int i; // [rsp+20h] [rbp-188h]
  int j; // [rsp+20h] [rbp-188h]
  int l; // [rsp+20h] [rbp-188h]
  int m; // [rsp+20h] [rbp-188h]
  int uid_map3; // [rsp+24h] [rbp-184h]
  int v9; // [rsp+28h] [rbp-180h]
  int v10; // [rsp+28h] [rbp-180h]
  int v_MAX_UINT; // [rsp+2Ch] [rbp-17Ch]
  int v12; // [rsp+30h] [rbp-178h]
  unsigned int v13; // [rsp+34h] [rbp-174h]
  int v14; // [rsp+38h] [rbp-170h]
  int v15; // [rsp+3Ch] [rbp-16Ch]
  int v16; // [rsp+40h] [rbp-168h]
  char str1; // [rsp+44h] [rbp-164h]
  char str2; // [rsp+5Fh] [rbp-149h]
  char v19; // [rsp+60h] [rbp-148h]
  int v20[52]; // [rsp+B0h] [rbp-F8h]
  int v21[4]; // [rsp+180h] [rbp-28h] BYREF

  if ( !flag_enc )
    return 0 L;
  v_MAX_UINT = 0x11111111;
  for ( i = 0; i < 14; ++i )
  {
    v20[i] = v_MAX_UINT ^ *((_DWORD *)qword_1400168F0 + i);
    v_MAX_UINT += 0x11111111;
  }
  // 相当于把 v16的首地址放在了 Block+200 处
  LOBYTE(v16) = *((_BYTE *)Block + 200);
  BYTE1(v16) = *((_BYTE *)Block + 202);
  BYTE2(v16) = *((_BYTE *)Block + 204);
  HIBYTE(v16) = *((_BYTE *)Block + 206);
  str1 = *((_BYTE *)Block + 208);
  for ( j = 1; j < 27; ++j ){
    // *((_BYTE *)&v16 + j + 4) = *((_BYTE *)v20 + 2 * j);
	// 可以多测试几次看看 v16 是不是固定的
	// v16是 flag{!!!_HAPPY_NEW_YEAR_2023!!!}
	v16[j+4] = v20[2*j]
  }
  str2 = *((_BYTE *)Block + 212);
  v19 = 0;
  for ( uid_map3 = v_MAX_UINT + uid_map; uid_map3 >= 0; uid_map3 = 2 * uid_map3 + 9 )
    ;
  //uid = 835429 时， uid_map3 = 0xCBF6CFF7
  // uid不变时，v21的内容也固定
  for ( l = 0; l < 4; ++l )
    v21[l] = (l + 1) * (uid_map3 + 1);
  v9 = 0;
  v15 = 0;
  // 一轮比较8个字节，共计4轮32字节，因此flag的长度算上头尾应当为32
  for ( m = 0; m < 7; m += 2 )
  {
	  // v15 的三个参数第一个由（截断的）flag决定，后面三个由uid决定
	  // 这个函数对 flag_enc 的切片做了变换，其返回值为 uid_map2 - 0x20*uid_map3，与flag无关
	  // 经测试，经内部32次循环后，函数的返回值必然为0
	  // 因此，底下所有的等式都必须成立，从 v16 中可以得知flag_enc 应当具有的形式
	  // uid = 835429 时， v21 = {0xCBF6CFF8, 0x97ED9FF0, 0x63E46FE8, 0x2FDB3FE0}
    v15 = sub_1400026E0( flag_enc + 4*m, v21, (unsigned int)uid_map3, uid_map2);
    //if ( *(&v16 + m) == *(_DWORD *)(flag_enc + 4 L * m) )
	// 不考虑类型，上句等价于
	if ( v16[m] == (_DWORD)flag_enc[4*m] ) // 请注意这里一次性比较了四个字节
      v14 = 0;
    else
      v14 = m + 1;
    //if ( *(&v16 + m + 1) == *(_DWORD *)(flag_enc + 4 L * (m + 1)) )
	if ( v16[m+1] == (_DWORD)flag_enc[4*m + 1] ) // 请注意这里一次性比较了四个字节
      v12 = 0;
    else
      v12 = m + 1;
    // v9可以选择不变， +0， +(m+1)，+2(m+1)，其中m为循环计数
    v9 += v12 + v14;
  }
  // 当 v9==v15时， m右移一位，此时m应为8/2 = 4，弹框提示success
  // 
  if ( v9 == v15 )
    v13 = m >> 1;
  else
    v13 = 3;
  return v13;
}

__int64 __fastcall sub_140002900(const wchar_t *flag_content, __int64 flag_enc)
{
  wchar_t v3; // [rsp+20h] [rbp-28h]
  int v4; // [rsp+24h] [rbp-24h]
  unsigned int v5; // [rsp+28h] [rbp-20h]
  __int64 v6; // [rsp+2Ch] [rbp-1Ch]

  HIDWORD(v6) = flag_content == 0 L;
  LODWORD(v6) = flag_enc == 0;
  if ( v6 )
    return 0 L;
  if ( wcslen(flag_content) % 8 )
    return 0 L;
  v4 = 0;
  v5 = 0;
  while ( flag_content[v4] )
  {
    v3 = flag_content[v4 + 8];
    flag_content[v4 + 8] = 0;
    // *(_DWORD *)(flag_enc + 4 * (int)v5) = sub_1400024A0(&flag_content[v4]);
	flag_enc[4*v5] = sub_1400024A0(&flag_content[v4]);
	v5++;
    v4 += 8;
    flag_content[v4] ^= v3;
  }
  return v5;
}

__int64 __fastcall sub_1400024A0(const wchar_t *flag_content_slice)
{
  int i; // [rsp+20h] [rbp-18h]
  unsigned int result; // [rsp+24h] [rbp-14h]

  result = 0;
  if ( wcslen(flag_content_slice) != 8 )
    return 0;
  for ( i = 0; i < 8; ++i )
  {
    result *= 16;
    if ( flag_content_slice[i] < 'a' || flag_content_slice[i] > 'f' ){
      if ( flag_content_slice[i] < 'A' || flag_content_slice[i] > 'F' ){
        if ('0' <= flag_content_slice[i] && flag_content_slice[i] <= '9' ){
          result += flag_content_slice[i] - '0';
		}
      }else {
        result += flag_content_slice[i] - '7';
      }
    }else{
      result += flag_content_slice[i] - 'W';
    }
  }
  return result;
}

__int64 __fastcall sub_1400026E0(unsigned int *flag_enc_slice, _DWORD *uid_map4, int uid_map3, unsigned int uid_map2)
{
  unsigned int v5; // [rsp+0h] [rbp-28h]
  unsigned int v6; // [rsp+4h] [rbp-24h]
  unsigned int i; // [rsp+8h] [rbp-20h]

  v5 = flag_enc_slice[0];
  v6 = flag_enc_slice[1];
  for ( i = 0; i < 0x20; ++i )
  {
    v6 -= (uid_map4[3] + (v5 >> 5)) ^ (uid_map2 + v5) ^ (uid_map4[2] + 16 * v5);
    v5 -= (uid_map4[1] + (v6 >> 5)) ^ (uid_map2 + v6) ^ (uid_map4[0] + 16 * v6);
    uid_map2 -= uid_map3;
  }
  flag_enc_slice[0] = v5;
  flag_enc_slice[1] = v6;
  return uid_map2;
}

__int64 __fastcall sub_140002110(const wchar_t *hwind, int a2)
{
  unsigned __int64 v2; // kr00_8
  int k; // [rsp+20h] [rbp-3A8h]
  int j; // [rsp+24h] [rbp-3A4h]
  int v6; // [rsp+28h] [rbp-3A0h]
  int v7; // [rsp+28h] [rbp-3A0h]
  int i; // [rsp+2Ch] [rbp-39Ch]
  int v9; // [rsp+30h] [rbp-398h]
  int v10; // [rsp+30h] [rbp-398h]
  unsigned int uid_map; // [rsp+38h] [rbp-390h]
  int v12; // [rsp+3Ch] [rbp-38Ch]
  int v13; // [rsp+40h] [rbp-388h]
  int v14; // [rsp+44h] [rbp-384h]
  unsigned int v15; // [rsp+48h] [rbp-380h]
  int v16[6]; // [rsp+58h] [rbp-370h] BYREF
  int v17[104]; // [rsp+70h] [rbp-358h] BYREF
  int Destination[104]; // [rsp+210h] [rbp-1B8h] BYREF

  v12 = wcslen(hwind);
  memcpy_s(Destination, 0x38u L, qword_1400168F0, 0x38u L);
  hwind[v12 - 1] ^= 0x7Du;
  v6 = -1;
  for ( i = a2 - 1; i >= 0; i = 2 * i + 9 )
    ;
  for ( j = 0; j < 4; ++j )
  {
    v16[j] = j + 1 + (j + 1) * i;
    hwind[j + 25] = hwind[j + 25] + j + 1 - 48;
  }
  memcpy_s(v17, 0x38u L, hwind + 5, 0x38u L);
  v9 = 3;
  uid_map = 0;
  for ( k = 0; k < 14; k += 2 )
  {
    v2 = (unsigned __int64)(unsigned int)v17[k] << 16;
    v17[k] = v6 ^ (v2 | HIDWORD(v2));
    sub_140001D70(&Destination[k], v16, (unsigned int)i);
    v7 = v6 + 286331153;
    v17[k + 1] = v7 ^ (HIWORD(v17[k + 1]) | (v17[k + 1] << 16));
    uid_map = sub_140001D70(&v17[k], v16, (unsigned int)i);
    v6 = v7 + 286331153;
    if ( Destination[k] == v17[k] )
      v14 = 0;
    else
      v14 = k + 1;
    v10 = v14 + v9;
    if ( Destination[k + 1] == v17[k + 1] )
      v13 = 0;
    else
      v13 = k + 1;
    v9 = v13 + v10;
  }
  if ( v9 == 3 )
    v15 = 0;
  else
    v15 = uid_map;
  return v15;
}